package unionfs

import (
	"fmt"
	"github.com/sirupsen/logrus"
	"os"
	"os/exec"
	"path"
	"strings"
)

var _ UnionFS = &Overlay{}

type Overlay struct {
	Lower  string
	Upper  string
	Work   string
	Merged string
}

func (o *Overlay) Mount(rootfs string, volumes []string) string {
	o.createLayer(rootfs)

	//dirs := "noxino,dirs=" + lower + ":" + upper
	//command := exec.Command("mount", "-t", "aufs", "-o", dirs, "none", merged)
	//if err := command.Run(); err != nil {
	//	logrus.Errorf("mount aufs %s error. %v", merged, err)
	//}

	dirs := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", o.Lower, o.Upper, o.Work)
	exec.Command("mount", "-t", "overlay", "overlay", "-o", dirs, o.Merged).Run()

	MountVolume(o.Merged, volumes)

	return o.Merged
}

func (o *Overlay) createLayer(rootfs string) {
	if _, err := os.Stat(rootfs); err != nil {
		os.Mkdir(rootfs, 0755)
	}

	o.Lower = path.Join(rootfs, "lower")
	if _, err := os.Stat(o.Lower); err != nil {
		os.Mkdir(o.Lower, 0755)
	}

	o.Upper = path.Join(rootfs, "upper")
	if _, err := os.Stat(o.Upper); err != nil {
		os.Mkdir(o.Upper, 0755)
	}

	o.Work = path.Join(rootfs, "work")
	if _, err := os.Stat(o.Work); err != nil {
		os.Mkdir(o.Work, 0755)
	}

	o.Merged = path.Join(rootfs, "merged")
	if _, err := os.Stat(o.Merged); err != nil {
		os.Mkdir(o.Merged, 0755)
	}

}

func MountVolume(merged string, volumes []string) error {
	for _, volume := range volumes {
		if volume == "" {
			return nil
		}

		volumeURLs := strings.Split(volume, ":")
		if len(volumeURLs) != 2 {
			return fmt.Errorf("Volume parameter err ")
		}

		hostURL := volumeURLs[0]

		if err := os.MkdirAll(hostURL, 0777); err != nil {
			logrus.Errorf("Mkdir hostURL %s error. %v", hostURL, err)
		}

		containerURL := path.Join(merged, volumeURLs[1])
		if err := os.MkdirAll(containerURL, 0777); err != nil {
			logrus.Errorf("Mkdir containerURL %s error. %v", containerURL, err)
		}

		dirs := "noxino,dirs=" + hostURL
		command := exec.Command("mount", "-t", "aufs", "-o", dirs, "none", containerURL)
		command.Stdout = os.Stdout
		command.Stderr = os.Stderr
		if err := command.Run(); err != nil {
			logrus.Errorf("mount volume err: %v", err)
		}
	}

	// 软链接是不可以的，是链接成功了，但是容器内部是读取不到外部主机的文件系统的，只能使用mount
	//lastDir, _ := path.Split(containerURL)
	//err := os.Remove(lastDir)
	//if err != nil {
	//	logrus.Errorf("Remove lastDir %s error. %v", lastDir, err)
	//}
	//
	//command := exec.Command("ln", "-s", hostURL, containerURL)
	//if err := command.Run(); err != nil {
	//	logrus.Errorf("Mount volume failed. %v", err)
	//}
	return nil
}

func (o *Overlay) Umount(rootfs string, volumes []string) {
	for _, volume := range volumes {
		if volume != "" {
			volumeURLs := strings.Split(volume, ":")
			if len(volumeURLs) != 2 {
				logrus.Error("Volume parameter err ")
			}

			join := path.Join(rootfs, "merged", volumeURLs[1])
			if err := exec.Command("umount", join).Run(); err != nil {
				logrus.Errorf("umount %s err: %v", join, err)
			}
		}
	}

	if err := exec.Command("umount", path.Join(rootfs, "merged")).Run(); err != nil {
		logrus.Error(err)
	}

	if err := os.RemoveAll(rootfs); err != nil {
		logrus.Error(err)
	}
}
